#include "driver_tm1637.h"

#define DIGT(a)   swap_bits(leddata[a])
const uint8_t ascii[128] =
{
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x6D, 0x00, 0x00, 0x20,
        0x39, 0x0F, 0x00, 0x00, 0x10, 0x40, 0x80, 0x52, 0x3F, 0x06,
        0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x00, 0x00,
        0x00, 0x48, 0x00, 0x53, 0x00, 0x77, 0x7C, 0x39, 0x5E, 0x79,
        0x71, 0x3D, 0x76, 0x30, 0x1E, 0x00, 0x38, 0x00, 0x54, 0x3F,
        0x73, 0x67, 0x50, 0x6D, 0x78, 0x3E, 0x00, 0x00, 0x00, 0x6E,
        0x5B, 0x39, 0x64, 0x00, 0x0F, 0x08, 0x20, 0x77, 0x7C, 0x58,
        0x5E, 0x79, 0x71, 0x3D, 0x74, 0x04, 0x1E, 0x00, 0x38, 0x00,
        0x54, 0x5C, 0x73, 0x67, 0x50, 0x6D, 0x78, 0x3E, 0x00, 0x00,
        0x00, 0x6E, 0x5B, 0x39, 0x30, 0x0F, 0x40, 0x00,
};

const unsigned char leddata[]={ 
 
                0x3F,  //"0"
                0x06,  //"1"
                0x5B,  //"2"
                0x4F,  //"3"
                0x66,  //"4"
                0x6D,  //"5"
                0x7D,  //"6"
                0x07,  //"7"
                0x7F,  //"8"
                0x6F,  //"9"
                0x77,  //"A"
                0x7C,  //"b"
                0x39,  //"C"
                0x5E,  //"d"
                0x79,  //"E"
                0x71,  //"F"
                
                0x76,  //"H"
                0x38,  //"L"
                0x37,  //"n"
                0x3E,  //"u"
                0x73,  //"P"
                0x5C,  //"o"
                0x40,  //"-"
                0x00,  //熄灭
                         };
const unsigned char brightness_level[] = {0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f};

//此函数需要根据实际的接线调整
uint8_t TM1637::swap_bits(uint8_t dat){
  uint8_t i,x,L,H;

  if(flip){
    for(i = 0; i < 3; i++)
    {
      x = 1 << i;
      L = dat & x;
      H = dat & (x << 3);
      dat = (dat & (~x)) | (H>>3);
      dat = (dat & (~(x << 3))) | (L<<3);
    }
  }
  return dat;  
}  

void TM1637::SetFlip(bool f){
  flip = f;
}

TM1637::TM1637(uint8_t CLK, uint8_t DIO){
  pin_clk = CLK;
  pin_dio = DIO;
  brightness = 6;
  flip = false;

  pinMode(pin_clk, OUTPUT);
  pinMode(pin_dio, OUTPUT);
}

void TM1637::Clear(void){

  driver_tm1637_start();
  
  driver_tm1637_cmd(0x40); // mode
  driver_tm1637_stop();
  driver_tm1637_start();
  driver_tm1637_cmd(0xc0); //  start address
  driver_tm1637_cmd(0);
  driver_tm1637_cmd(0);
  driver_tm1637_cmd(0);
  driver_tm1637_cmd(0);
  driver_tm1637_cmd(0);
  driver_tm1637_cmd(0);

  driver_tm1637_stop();
  driver_tm1637_start();
  driver_tm1637_cmd(brightness_level[brightness>7?7:brightness]);   // 显示亮度
  driver_tm1637_stop();

}

void TM1637::SetBrightness(uint8_t br){
  if (br > 7) br = 7;
  brightness = br;
}

uint8_t TM1637::GetBrightness(void){
  return brightness;
}

void TM1637::SetSegmentDisplayNum(uint8_t Seg, char cont){

  driver_tm1637_start();  
  driver_tm1637_cmd(0x44); // 模式：固定位置
  driver_tm1637_stop();
  driver_tm1637_start();

  driver_tm1637_cmd(0xc0 | ((Seg > 5)?5:Seg)); //  起始地址
  driver_tm1637_cmd(swap_bits(ascii[cont]));
  driver_tm1637_stop();
  driver_tm1637_start();
  driver_tm1637_cmd(brightness_level[brightness>7?7:brightness]);   // 显示亮度
  driver_tm1637_stop();
}

// 显示4位数字, 0000-9999
void TM1637::Display4Num(uint8_t offset, uint32_t num){
  Clear();
  driver_tm1637_start();
  driver_tm1637_cmd(0x40); // mode
  driver_tm1637_stop();
  driver_tm1637_start();
  
  if (!flip){
    driver_tm1637_cmd(0xc0 + offset); //  start address
    driver_tm1637_cmd(DIGT(num/1000%10));
    driver_tm1637_cmd(DIGT(num/100%10));
    driver_tm1637_cmd(DIGT(num/10%10));
    driver_tm1637_cmd(DIGT(num%10));
  }
  else{
    driver_tm1637_cmd(0xc0 +(2 - offset)); //  start address
    driver_tm1637_cmd(DIGT(num%10));
    driver_tm1637_cmd(DIGT(num/10%10));
    driver_tm1637_cmd(DIGT(num/100%10));
    driver_tm1637_cmd(DIGT(num/1000%10));
  }
  driver_tm1637_stop();
  driver_tm1637_start();
  driver_tm1637_cmd(brightness_level[brightness>7?7:brightness]);   // 显示亮度
  driver_tm1637_stop();
}

void TM1637::DisplayDash4Num(uint8_t offset, uint32_t num){
  Clear();
  driver_tm1637_start();
  driver_tm1637_cmd(0x40); // mode
  driver_tm1637_stop();
  driver_tm1637_start();
  
  if (!flip){
    driver_tm1637_cmd(0xc0 + offset); //  start address
    driver_tm1637_cmd(DIGT(num/1000%10));
    driver_tm1637_cmd(DIGT(num/100%10));
    driver_tm1637_cmd(DIGT(22));
    driver_tm1637_cmd(DIGT(num/10%10));
    driver_tm1637_cmd(DIGT(num%10));
  }
  else{
    driver_tm1637_cmd(0xc0 +(1 - offset)); //  start address
    driver_tm1637_cmd(DIGT(num%10));
    driver_tm1637_cmd(DIGT(num/10%10));
    driver_tm1637_cmd(DIGT(22));
    driver_tm1637_cmd(DIGT(num/100%10));
    driver_tm1637_cmd(DIGT(num/1000%10));
  }
  driver_tm1637_stop();
  driver_tm1637_start();
  driver_tm1637_cmd(brightness_level[brightness>7?7:brightness]);   // 显示亮度
  driver_tm1637_stop();
}

void TM1637::Display1Num(uint8_t posi, uint8_t num){  
  if (posi >= WEI || num > 9) return;
  driver_tm1637_start();
  driver_tm1637_cmd(0x44); // 模式：固定位置
  driver_tm1637_stop();
  driver_tm1637_start();

  driver_tm1637_cmd(0xc0 | (posi % WEI)); // 起始地址
  driver_tm1637_cmd(DIGT(num));   // 显示值
  
  driver_tm1637_stop();
}
// 显示多位数字, 0-99999
void TM1637::DisplayNum(uint8_t offset, uint32_t num){  
  Clear();

  int i = 100000, j;
  if (!flip){
    j = 0 + offset;
    if (0 == num){
      Display1Num(j, 0);
    }
    else{
      for (; i != 0; i/=10){
        if (num/i%10) break;
      }
      for (; i != 0; i/=10){
        Display1Num(j, num/i%10);
        j++;
      }
    }
  }
  else{
    j = 5 - offset;
    if (0 == num){
      Display1Num(j, 0);
    }
    else{
      for (; i != 0; i/=10){
        if (num/i%10) break;
      }
      for (; i != 0; i/=10){
        Display1Num(j, num/i%10);
        j--;
      }
    }
  }

  driver_tm1637_start();
  driver_tm1637_cmd(brightness_level[brightness>7?7:brightness]);   // 显示亮度
  driver_tm1637_stop();
}

void TM1637::Display6Num(uint32_t num){
  
  driver_tm1637_start();
  driver_tm1637_cmd(0x40); // mode
  driver_tm1637_stop();
  driver_tm1637_start();
  driver_tm1637_cmd(0xc0); //  start address
  if (!flip){
    driver_tm1637_cmd(DIGT(num/100000%10));
    driver_tm1637_cmd(DIGT(num/10000%10));
    driver_tm1637_cmd(DIGT(num/1000%10));
    driver_tm1637_cmd(DIGT(num/100%10));
    driver_tm1637_cmd(DIGT(num/10%10));
    driver_tm1637_cmd(DIGT(num%10));
  }
  else{
    driver_tm1637_cmd(DIGT(num%10));
    driver_tm1637_cmd(DIGT(num/10%10));
    driver_tm1637_cmd(DIGT(num/100%10));
    driver_tm1637_cmd(DIGT(num/1000%10));
    driver_tm1637_cmd(DIGT(num/10000%10));
    driver_tm1637_cmd(DIGT(num/100000%10)); 
  }
  driver_tm1637_stop();
  driver_tm1637_start();
  driver_tm1637_cmd(brightness_level[brightness>7?7:brightness]);   // 显示亮度
  driver_tm1637_stop();
}

void TM1637::driver_tm1637_start(void){
  digitalWrite(pin_dio, HIGH);
  digitalWrite(pin_clk, HIGH);
  DELAY;
  digitalWrite(pin_dio, LOW);
  DELAY;
  digitalWrite(pin_clk, LOW);
}

void TM1637::driver_tm1637_stop(void){
  digitalWrite(pin_dio, LOW);
  digitalWrite(pin_clk, LOW);
  DELAY;
  digitalWrite(pin_clk, HIGH);
  DELAY;
  digitalWrite(pin_dio, HIGH);
}

void TM1637::driver_tm1637_cmd(uint8_t dat){
  uint8_t ack;
  digitalWrite(pin_dio, LOW);
  digitalWrite(pin_clk, LOW);

  for (int i = 0; i < 8; i++){
    digitalWrite(pin_dio, (dat & 0x01) ? HIGH : LOW);
    digitalWrite(pin_clk, HIGH);
    dat >>= 1;
    digitalWrite(pin_clk, LOW);
  }
  digitalWrite(pin_dio, HIGH);
  digitalWrite(pin_clk, HIGH);
  pinMode(pin_dio, INPUT);
  
  if ((ack = digitalRead(pin_dio)) == 0) {  // TODO:这里需要回头优化一下
    pinMode(pin_dio, INPUT);  
    digitalWrite(pin_dio, LOW);
  }
  //digitalWrite(pin_clk, LOW);
  pinMode(pin_dio, OUTPUT);
}




